﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace LevelEditor.View.Controls.Adorners
{
    public class SelectionAdorner : Adorner
    {
        public event EventHandler SelectionEnded;

        public void OnSelectionEnded()
        {
            if (SelectionEnded != null)
            {
                SelectionEnded(null, new EventArgs());
            }
        }

        private FrameworkElement scene;
        private FrameworkElement workArea;

        public Rect SelectionRectangle;
        private SolidColorBrush renderBrush;
        private Pen renderPen;

        private Point origPos;

        public bool selectionStarted = false;
        public bool SelectionStarted
        { 
            
            get { return selectionStarted; }
            set
            {
                if (selectionStarted == value)
                    return;

                selectionStarted = value;

                if (!selectionStarted)
                    this.OnSelectionEnded();
            }
        }
        public Rect SelectionRectangleRelativeToScene {
            get {
            
                Point relativePoint = scene.TransformToAncestor(AdornedElement)
                              .Transform(new Point(0, 0));

                //Here i added the scaling division to have an accurate selection when zoomed in or out
                double scaleX = (double)scene.LayoutTransform.GetValue(ScaleTransform.ScaleXProperty);
                double scaleY = (double)scene.LayoutTransform.GetValue(ScaleTransform.ScaleYProperty);

                return new Rect(new Point(SelectionRectangle.X/scaleX - relativePoint.X/scaleX, SelectionRectangle.Y/scaleY - relativePoint.Y/scaleY),
                                new Size(SelectionRectangle.Width/scaleX, SelectionRectangle.Height/scaleY));
            }
        }

        private Window mainWindowOwner;

        public SelectionAdorner(UIElement adornedElement, FrameworkElement scene, FrameworkElement workArea)
               : base(adornedElement)
        {
            this.scene = scene;
            this.workArea = workArea;

            this.scene.MouseDown += workArea_MouseDown;//To enable selection inside the sceneCanvas
            (this.workArea.Parent as FrameworkElement).PreviewMouseDown += workArea_MouseDown; //To enable selection outside the sceneCanvas

            adornedElement.MouseUp += workArea_MouseUp;

            mainWindowOwner = Window.GetWindow(adornedElement);

            this.IsHitTestVisible = false;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            if (!SelectionStarted)
                return;

            if (this.renderBrush == null)
            {
                this.renderBrush = new SolidColorBrush(Colors.Transparent);
                this.renderBrush.Freeze();
            }
            if (this.renderPen == null)
            {
                this.renderPen = new Pen(new SolidColorBrush(Colors.Gray), .8);
                this.renderPen.DashStyle = DashStyles.Dash;
                this.renderPen.Freeze();
            }

            drawingContext.DrawRectangle(this.renderBrush, this.renderPen, this.SelectionRectangle);
        }

        protected void workArea_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //To avoid double triggering selection when starting selection inside the scene canvas
            if (sender == workArea.Parent)
            {
                Point mousePos = e.GetPosition(scene);
                if (new Rect(new Point(0, 0), scene.DesiredSize).Contains(mousePos))
                    return;
            }

            if (SelectionStarted) return;

            SelectionStarted = true;

            origPos = Mouse.GetPosition(AdornedElement);

            SelectionRectangle = new Rect(origPos, new Size(0, 0));
            SelectionRectangle.X = Math.Round(SelectionRectangle.X);
            SelectionRectangle.Y = Math.Round(SelectionRectangle.Y);

            mainWindowOwner.MouseMove += workArea_MouseMove;
            mainWindowOwner.MouseLeftButtonUp += workArea_MouseUp;
        }

        protected void workArea_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            SelectionStarted = false;

            mainWindowOwner.MouseMove -= workArea_MouseMove;
            mainWindowOwner.MouseLeftButtonUp -= workArea_MouseUp;

            this.InvalidateVisual();
        }

        protected void workArea_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (SelectionStarted && e.MouseDevice.LeftButton == MouseButtonState.Pressed)
            {
                Point pos = e.GetPosition(AdornedElement);

                if (pos.X <= origPos.X)
                {
                    SelectionRectangle.X = pos.X;
                    SelectionRectangle.Width = origPos.X - pos.X;
                }
                else
                {
                    SelectionRectangle.X = origPos.X;
                    SelectionRectangle.Width = pos.X - origPos.X;
                }

                if (pos.Y <= origPos.Y)
                {
                    SelectionRectangle.Y = pos.Y;
                    SelectionRectangle.Height = origPos.Y - pos.Y;
                }
                else
                {
                    SelectionRectangle.Y = origPos.Y;
                    SelectionRectangle.Height = pos.Y - origPos.Y;
                }

            }
            else {
                SelectionStarted = false;
            }

            this.InvalidateVisual();
        }
    }
}
